#include <stdio.h>



#include <stdlib.h>
#include <event.h>
#include <string.h>
#include <libconfig.h>
#include <openssl/evp.h>
#include <openssl/rand.h>
#include "base64.h"

#include <uuid/uuid.h>

#include "db.h"
#include "log.h"
#include "auth.h"

#include "mqtt.h"
#include "http.h"

#include "event2/http.h"

#include "event2/http_struct.h"

struct evhttp *G_http_server;

#define MAX_BUFFER_LEN 1024

#define SALTLEN 12

#define KEY_LENGTH      24

int gen_uuid(char *buf) {
    uuid_t uuid;
    if (!buf) {
        DEBUG("create USER-UUID error");
        return -1;
    }
    uuid_clear(uuid);
    uuid_generate(uuid);
    if (uuid_is_null(uuid)) {
        DEBUG("generate UUID failed");
        return -1;
    }
    uuid_unparse_upper(uuid, buf);
    return 0;
}

int output_new_password(const char* password, char* secret) {
    int iterations = 901, rc, blen;
    unsigned char saltbytes[SALTLEN];
    char *salt, *b64;
    unsigned char key[128];



    rc = RAND_bytes(saltbytes, SALTLEN);
    if (rc == 0) {
        DEBUG("Cannot get random bytes for salt!\n");
        return 2;
    }

    base64_encode(saltbytes, SALTLEN, &salt);


    int saltlen;
    saltlen = strlen(salt);

    PKCS5_PBKDF2_HMAC(password, strlen(password),
            (unsigned char *) salt, saltlen,
            iterations,
            EVP_sha256(), KEY_LENGTH, key);



    blen = base64_encode(key, KEY_LENGTH, &b64);
    if (blen > 0) {
        sprintf(secret, "PBKDF2$%s$%d$%s$%s",
                "sha256",
                iterations,
                salt,
                b64);
        free(salt);
        free(b64);
    }


    return 0;
}

void setconf(struct evhttp_request *req, void *arg) {
    int errCode = 0;
    struct evkeyvalq params;
    const char *uri = NULL;
    const char *secret = NULL;
    const char *nasip = NULL;
    const char *devid = NULL;


    if (req == NULL) {
        DEBUG("====line:%d,%s\n", __LINE__, "input param req is null.");
        return;
    }

    struct evbuffer *repBuf = evbuffer_new();
    //get_post_message(buf, req);  //获取请求数据，一般是json格式的数据

    do {
        uri = evhttp_request_get_uri(req);
        if (uri == NULL) {
            DEBUG("URI 'auth' : not found URI");
            errCode = -1;
            break;
        }
        DEBUG("URI auth: %s", uri);

        if (evhttp_parse_query(uri, &params) != 0) {
            DEBUG("URI 'auth': parse query string failed");
            errCode = -1;
            break;
        }
        nasip = evhttp_find_header(&params, "nasip");
        if (nasip == NULL) {
            DEBUG("URI 'auth': not found parameter 'nasip'");
            evhttp_clear_headers(&params);
            errCode = -1;
            break;
        }
        devid = evhttp_find_header(&params, "devid");
        if (devid == NULL) {
            DEBUG("URI 'auth': not found parameter 'devid'");
            evhttp_clear_headers(&params);
            errCode = -1;
            break;
        }
        secret = evhttp_find_header(&params, "secret");
        if (secret == NULL) {
            DEBUG("URI 'auth': not found parameter 'secret'");
            evhttp_clear_headers(&params);
            errCode = -1;
            break;
        }

        evhttp_clear_headers(&params);
    } while (0);




    evbuffer_add_printf(repBuf, "{\"code\":%d}", errCode);
    evhttp_send_reply(req, 200, "OK", repBuf);
    evbuffer_free(repBuf);

}

void getconf(struct evhttp_request *req, void *arg) {
    int errCode = 0;
    struct evkeyvalq params;
    const char *uri = NULL;
    const char *secret = NULL;
    const char *nasip = NULL;
    const char *devid = NULL;


    if (req == NULL) {
        DEBUG("====line:%d,%s\n", __LINE__, "input param req is null.");
        return;
    }

    struct evbuffer *repBuf = evbuffer_new();
    //get_post_message(buf, req);  //获取请求数据，一般是json格式的数据

    do {
        uri = evhttp_request_get_uri(req);
        if (uri == NULL) {
            DEBUG("URI 'auth' : not found URI");
            errCode = -1;
            break;
        }
        DEBUG("URI auth: %s", uri);

        if (evhttp_parse_query(uri, &params) != 0) {
            DEBUG("URI 'auth': parse query string failed");
            errCode = -1;
            break;
        }
        nasip = evhttp_find_header(&params, "nasip");
        if (nasip == NULL) {
            DEBUG("URI 'auth': not found parameter 'nasip'");
            evhttp_clear_headers(&params);
            errCode = -1;
            break;
        }
        devid = evhttp_find_header(&params, "devid");
        if (devid == NULL) {
            DEBUG("URI 'auth': not found parameter 'devid'");
            evhttp_clear_headers(&params);
            errCode = -1;
            break;
        }
        secret = evhttp_find_header(&params, "secret");
        if (secret == NULL) {
            DEBUG("URI 'auth': not found parameter 'secret'");
            evhttp_clear_headers(&params);
            errCode = -1;
            break;
        }

        evhttp_clear_headers(&params);
    } while (0);




    evbuffer_add_printf(repBuf, "{\"code\":%d}", errCode);
    evhttp_send_reply(req, 200, "OK", repBuf);
    evbuffer_free(repBuf);

}

void regdev(struct evhttp_request *req, void *arg) {
    int errCode = 0;
    struct evkeyvalq params;
    const char *uri = NULL;
    char secret[256] = {0};
    const char *nasip = NULL;
    const char *devid = NULL;
    const char *mac = NULL;
    char uuid[64] = {0};
    unsigned char pubkey[2018] = {0};

    if (req == NULL) {
        DEBUG("====line:%d,%s\n", __LINE__, "input param req is null.");
        return;
    }

    struct evbuffer *repBuf = evbuffer_new();
    //get_post_message(buf, req);  //获取请求数据，一般是json格式的数据

    do {
        uri = evhttp_request_get_uri(req);
        if (uri == NULL) {
            DEBUG("URI 'regdev' : not found URI");
            errCode = -1;
            break;
        }
        DEBUG("URI auth: %s", uri);

        if (evhttp_parse_query(uri, &params) != 0) {
            DEBUG("URI 'regdev': parse query string failed");
            errCode = -1;
            break;
        }
                mac = evhttp_find_header(&params, "mac");
        if (mac == NULL) {
            DEBUG("URI 'regdev': not found parameter 'mac'");
            evhttp_clear_headers(&params);
            errCode = -1;
            break;
        }
        
        nasip = evhttp_find_header(&params, "nasip");
        if (nasip == NULL) {
            DEBUG("URI 'regdev': not found parameter 'nasip'");
            evhttp_clear_headers(&params);
            errCode = -1;
            break;
        }
        devid = evhttp_find_header(&params, "devid");
        if (devid == NULL) {
            DEBUG("URI 'regdev': not found parameter 'devid'");
            evhttp_clear_headers(&params);
            errCode = -1;
            break;
        }
/*
      size_t post_size = 0;
        
        post_size = evbuffer_get_length(req->input_buffer); //获取数据长度
        printf("====line:%d,post len:%d\n", __LINE__, post_size);
        if (post_size <= 0) {
            printf("====line:%d,post msg is empty!\n", __LINE__);
            return;
        } else {
            size_t copy_len = post_size > 1024 ? 1024 : post_size;
            //printf("====line:%d,post len:%d, copy_len:%d\n",__LINE__,post_size,copy_len);
            memcpy(pubkey, evbuffer_pullup(req->input_buffer, -1), copy_len);

            DEBUG("public key:\n%s\n", pubkey);

        }
*/

        //  evhttp_clear_headers(&params);
    } while (0);

  //  gen_uuid(uuid);
    output_new_password(devid, secret);

    if (regist_dev(mac, nasip, secret,pubkey) < 0) {
        
           update_acu((char*)mac,  nasip, pubkey);
        
        errCode = -1;
    }
    if (errCode == 0) {
        DEBUG("%s", secret);

        evbuffer_add_printf(repBuf, "{\"code\":%d,\"secret\":\"%s\"}", errCode, uuid);
    } else {
        evbuffer_add_printf(repBuf, "{\"code\":%d }", errCode);
    }
    evhttp_send_reply(req, 200, "OK", repBuf);
    evbuffer_free(repBuf);

}

void update(struct evhttp_request *req, void *arg) {
    int errCode = 0;
    struct evkeyvalq params;
    const char *uri = NULL;
    const char *mac = NULL;
    const char *nasip = NULL;
    const char *devid = NULL;
    const char *sessionid = NULL;

    if (req == NULL) {
        DEBUG("====line:%d,%s\n", __LINE__, "input param req is null.");
        return;
    }

    struct evbuffer *repBuf = evbuffer_new();
    //get_post_message(buf, req);  //获取请求数据，一般是json格式的数据

    do {
        uri = evhttp_request_get_uri(req);
        if (uri == NULL) {
            DEBUG("URI 'login' : not found URI");
            errCode = -1;
            break;
        }
        DEBUG("URI auth: %s", uri);

        if (evhttp_parse_query(uri, &params) != 0) {
            DEBUG("URI 'auth': parse query string failed");
            errCode = -1;
            break;
        }
        nasip = evhttp_find_header(&params, "nasip");
        if (nasip == NULL) {
            DEBUG("URI 'login': not found parameter 'nasip'");
            evhttp_clear_headers(&params);
            errCode = -1;
            break;
        }
        devid = evhttp_find_header(&params, "devid");
        if (devid == NULL) {
            DEBUG("URI 'login': not found parameter 'devid'");
            evhttp_clear_headers(&params);
            errCode = -1;
            break;
        }
        mac = evhttp_find_header(&params, "mac");
        if (mac == NULL) {
            DEBUG("URI 'login': not found parameter 'mac'");
            evhttp_clear_headers(&params);
            errCode = -1;
            break;
        }
        //  sessionid = evhttp_find_header(&params, "sessionid");
/*
        size_t post_size = 0;
        unsigned char pubkey[2018] = {0};
        post_size = evbuffer_get_length(req->input_buffer); //获取数据长度
        printf("====line:%d,post len:%d\n", __LINE__, post_size);
        if (post_size <= 0) {
            printf("====line:%d,post msg is empty!\n", __LINE__);
            return;
        } else {
            size_t copy_len = post_size > 1024 ? 1024 : post_size;
            //printf("====line:%d,post len:%d, copy_len:%d\n",__LINE__,post_size,copy_len);
            memcpy(pubkey, evbuffer_pullup(req->input_buffer, -1), copy_len);

            DEBUG("public key:\n%s\n", pubkey);

        }
*/

        // evhttp_clear_headers(&params);
    } while (0);

    int id = login_dev(mac, nasip, devid);
    printf("++++++++%d\n", id);

    evbuffer_add_printf(repBuf, "{\"code\":%d}", errCode);
    evhttp_send_reply(req, 200, "OK", repBuf);
    evbuffer_free(repBuf);

}

void login(struct evhttp_request *req, void *arg) {
    int errCode = 0;
    struct evkeyvalq params;
    const char *uri = NULL;
    const char *secret = NULL;
    const char *nasip = NULL;
    const char *devid = NULL;
    const char *sessionid = NULL;

    if (req == NULL) {
        DEBUG("====line:%d,%s\n", __LINE__, "input param req is null.");
        return;
    }

    struct evbuffer *repBuf = evbuffer_new();
    //get_post_message(buf, req);  //获取请求数据，一般是json格式的数据

    do {
        uri = evhttp_request_get_uri(req);
        if (uri == NULL) {
            DEBUG("URI 'login' : not found URI");
            errCode = -1;
            break;
        }
        DEBUG("URI auth: %s", uri);

        if (evhttp_parse_query(uri, &params) != 0) {
            DEBUG("URI 'auth': parse query string failed");
            errCode = -1;
            break;
        }
        nasip = evhttp_find_header(&params, "nasip");
        if (nasip == NULL) {
            DEBUG("URI 'login': not found parameter 'nasip'");
            evhttp_clear_headers(&params);
            errCode = -1;
            break;
        }
        devid = evhttp_find_header(&params, "devid");
        if (devid == NULL) {
            DEBUG("URI 'login': not found parameter 'devid'");
            evhttp_clear_headers(&params);
            errCode = -1;
            break;
        }
        secret = evhttp_find_header(&params, "mac");
        if (secret == NULL) {
            DEBUG("URI 'login': not found parameter 'mac'");
            evhttp_clear_headers(&params);
            errCode = -1;
            break;
        }
        sessionid = evhttp_find_header(&params, "sessionid");
        if (secret == NULL) {
            DEBUG("URI 'pubkey': not found parameter 'sessionid'");
            evhttp_clear_headers(&params);
            errCode = -1;
            break;
        }
        // evhttp_clear_headers(&params);
    } while (0);




    evbuffer_add_printf(repBuf, "{\"code\":%d}", errCode);
    evhttp_send_reply(req, 200, "OK", repBuf);
    evbuffer_free(repBuf);

}

void coa(struct evhttp_request *req, void *arg) {
    int errCode = 0;
    struct evkeyvalq params;
    struct coa_rep* coa_msg;
    if (req == NULL) {
        printf("====line:%d,%s\n", __LINE__, "input param req is null.");
        return;
    }
    char buf[1024] = {0};
    struct evbuffer *repBuf = evbuffer_new();
    //get_post_message(buf, req);  //获取请求数据，一般是json格式的数据

    size_t post_size = 0;

    post_size = evbuffer_get_length(req->input_buffer); //获取数据长度
    printf("====line:%d,post len:%d\n", __LINE__, post_size);
    if (post_size <= 0) {
        printf("====line:%d,post msg is empty!\n", __LINE__);
        return;
    } else {
        size_t copy_len = post_size > 1024 ? 1024 : post_size;
        //printf("====line:%d,post len:%d, copy_len:%d\n",__LINE__,post_size,copy_len);
        memcpy(buf, evbuffer_pullup(req->input_buffer, -1), copy_len);
        coa_msg = (struct coa_rep*) buf;
        coa_msg->coa_flag = ntohl(coa_msg->coa_flag);
        coa_msg->msg.len = ntohl(coa_msg->msg.len);
        coa_msg->msg.off = ntohl(coa_msg->msg.off);
        printf("+++++++%d\n", coa_msg->coa_flag);
        if (coa_msg->coa_flag == 1) {
            radcliCOAACKRep(G_auth.radDM, &coa_msg->msg, &coa_msg->msg.from);
            DEBUG("CoA-ACK");
        } else {
            radcliCOANAKRep(G_auth.radDM, &coa_msg->msg, &coa_msg->msg.from);
            DEBUG("CoA-NAK");
        }
    }


    evbuffer_add_printf(repBuf, "{\"code\":%d}", errCode);
    evhttp_send_reply(req, 200, "OK", repBuf);
    evbuffer_free(repBuf);

}

int httpServerInit(struct event_base *base, const char *addr, uint32_t port) {

    struct evhttp_bound_socket *bound = NULL;

    G_http_server = evhttp_new(base);
    if (G_http_server == NULL) {
        DEBUG("new libevent http server failed");
        return -1;
    }




    evhttp_set_cb(G_http_server, "/coa", coa, NULL);
    evhttp_set_cb(G_http_server, LOGIN_DEVICE, login, NULL);
    evhttp_set_cb(G_http_server, REG_DEVICE, regdev, NULL);
    evhttp_set_cb(G_http_server, UPDATE, update, NULL);
    bound = evhttp_bind_socket_with_handle(G_http_server, addr, port);
    if (bound == NULL) {
        DEBUG("libevent http bind socket failed");
        evhttp_free(G_http_server);
        return -1;
    }
    DEBUG("Listen HTTP Address = %s, port = %u", addr, port);

    return 0;
}